#ifndef MSC_STACK_H
#define MSC_STACK_H

#include "mem_base.h"
#include <string.h>

//c stack
typedef struct ms_stack_item_s{
    struct ms_stack_item_s* next;
    char p[0];
}ms_stack_item_t, *ms_stack_item;

typedef ms_class_t ms_stack_funs;

typedef struct ms_stack_s{
    ms_alloc_t* ac;
    struct ms_stack_item_s* top;
    size_t size;
    size_t count;
    ms_stack_funs fs;
}ms_stack_t, *ms_stack;


CPUBLIC ms_stack ms_stack_create(ms_alloc_t* ac, size_t size, ms_stack_funs* fs) {
    if (!ac) {
        ac = ms_global_alloc();
    }
    ms_stack s = (ms_stack)ms_allocate(ac, sizeof(ms_stack_t));
    if (s) {
        s->ac = ac;
        s->top = NULL;
        if (size)
            s->size = size;
        else
            s->size = msc_size_ptr_;
        s->count = 0;
        ms_type_initclass(&s->fs, fs);
    }
    return s;
}

CPUBLIC void ms_stack_clear(ms_stack s) {
    if (s) {
        ms_stack_item si = s->top;
        while (si) {
            ms_stack_item item = si;
            si = si->next;
            s->fs.destroy(item->p);
            ms_deallocate(s->ac, item);
        }
        s->top = NULL;
        s->count = 0;
    }
}

CPUBLIC void ms_stack_destory(ms_stack s) {
#ifdef _IF_NULL_
    if (s) {
#endif
    ms_stack_clear(s);
    ms_deallocate(s->ac, s);
#ifdef _IF_NULL_
    }
#endif
}

CPUBLIC bool ms_stack_empty(ms_stack s) {
    return (NULL == s) || (NULL == s->top);
}

CPUBLIC size_t ms_stack_size(ms_stack s) {
#ifdef _IF_NULL_
    if (s) {
#endif
    return s->count;
#ifdef _IF_NULL_
    }
    return 0;
#endif
}

CPUBLIC bool ms_stack_push(ms_stack s, void* data) {
#ifdef _IF_NULL_
    if (s) {
#endif
    ms_stack_item item = (ms_stack_item)ms_allocate(s->ac, sizeof(ms_stack_item_t)+s->size);
    if (item) {
        s->fs.construct(item->p);
        s->fs.copy(item->p, data);
        item->next = s->top;
        s->top = item;
        ++s->count;
        return true;
    }
#ifdef _IF_NULL_
    }
#endif
    return false;
}

CPUBLIC void ms_stack_pop(ms_stack s) {
#ifdef _IF_NULL_
    if (s) {
#endif
    ms_stack_item item = s->top;
    if (item) {
        s->top = item->next;
        ms_deallocate(s->ac, item);
        --s->count;
    }
#ifdef _IF_NULL_
    }
#endif
}

CPUBLIC void* ms_statck_top(ms_stack s) {
#ifdef _IF_NULL_
    if (!ms_stack_empty(s)) {
#endif
    return s->top->p;
#ifdef _IF_NULL_
    }
    return NULL;
#endif
}

#define ms_stack_push_front ms_statck_push
#define ms_stack_pop_front ms_statck_pop
#define ms_statck_front ms_stack_top

#endif // MSC_STACK_H
